package Wires.popup.actions;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionDelegate;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;

import Wires.ActualParameter;
import Wires.ConnectableElement;
import Wires.FormalParameter;
import Wires.GenericTransformation;
import Wires.IdentityTransformation;
import Wires.Library;
import Wires.LibraryRef;
import Wires.Model2TextTransformation;
import Wires.ModelType;
import Wires.Query;
import Wires.TransformationType;
import Wires.WiresElement;
import Wires.exep.IdOutParamNotFoundException;
import Wires.exep.InitialModelsNotFoundException;
import Wires.exep.LibraryNotFoundException;
import Wires.exep.MetamodelNotFoundException;
import Wires.exep.QueryFailedException;
import Wires.exep.ResourceNotFoundException;
import Wires.exep.TCSExtractionFailedException;
import Wires.exep.TypeNotFoundException;
import Wires.impl.WiresLauncher;

public class ExecuteWiresModel implements IObjectActionDelegate {

	protected static final String Activator = null;
	private Shell shell;
	String filePath;
	String path;
	private String errorMessage = "";
	boolean ok = false;
	
	/**
	 * Constructor for Action1.
	 */
	public ExecuteWiresModel() {
		super();
	}

	/**
	 * @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
	 */
	public void setActivePart(IAction action, IWorkbenchPart targetPart) {
		shell = targetPart.getSite().getShell();
	}

	/**
	 * @see IActionDelegate#run(IAction)
	 */
	public void run(IAction action) {
		Job job = new Job("Executing Wires* Model") {						
			protected IStatus run(IProgressMonitor monitor) {
				try{
					WiresLauncher.run(filePath);
					
					ok = true;									
					
					return Status.OK_STATUS;
				}catch(InitialModelsNotFoundException e){
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							MessageDialog.openError(
									shell,
									"Wires Error",
									"Error: "+ "No initial models!");
						}
					}); 

					return Status.CANCEL_STATUS;
					
				}catch(IdOutParamNotFoundException e){
					WiresElement wEl = e.getWiresElement();
					String paramName = ((ActualParameter)wEl).getName();
					String transName = ((IdentityTransformation)((ActualParameter)wEl).eContainer()).getName();
					
					errorMessage = "The input parameter '" + paramName + 
									"' does not have an output parameter with the" +
									" same name in the identity trasnformation '" + 
									transName + "'";
					
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							MessageDialog.openError(
									shell,
									"Wires Error",
									"Error: "+ errorMessage);
						}
					}); 

					return Status.CANCEL_STATUS;
					
				}catch(TCSExtractionFailedException e){
					WiresElement wEl = e.getWiresElement();
					if (wEl instanceof ActualParameter){
						String transName = ((GenericTransformation)((ActualParameter)wEl).eContainer()).getName();
						errorMessage = "ATL code extraction failed at generic transformation '" +
								   transName + "'";
					}else if (wEl instanceof Model2TextTransformation){
						String transName = ((Model2TextTransformation)wEl).getName();
						errorMessage = "TCS extraction failed at Model 2 Text Transformation '" +
								   transName + "'";
					}
					
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							MessageDialog.openError(
									shell,
									"Wires Error",
									"Error: "+ errorMessage);
						}
					}); 
					
					return Status.CANCEL_STATUS;
					
				}catch(LibraryNotFoundException e){
					LibraryRef lib = e.getLibraryRef();					
					String libRefName = lib.getName();
					String containerName = "";
					try {
						containerName = ((TransformationType)lib.eContainer()).getName();
					} catch (Exception e1) {
						containerName = ((Library)lib.eContainer()).getName();
					}
					
					String concept = "";
					if (lib instanceof TransformationType){
						concept = "transformation type";
					}else if (lib instanceof Library){
						concept = "library";
					}
					
					errorMessage = "Library not found at library ref '" +
								   libRefName + "' of " + concept + " '" + containerName + "'";
					
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							MessageDialog.openError(
									shell,
									"Wires Error",
									"Error: "+ errorMessage);
						}
					}); 
					
					return Status.CANCEL_STATUS;
					
				}catch(MetamodelNotFoundException e){
					WiresElement wEl = e.getWiresElement();					
					
					if (wEl instanceof FormalParameter){
						String paramName = ((FormalParameter)wEl).getName() +
											":" + ((FormalParameter)wEl).getTypeName();
						String tType =  ((TransformationType)((FormalParameter)wEl).eContainer()).getName();						
						errorMessage = "Please fill the typeEl attribute in the parameter '" + paramName +
									   "' of the transformation '" + tType + " '";
					}else if (wEl instanceof ModelType){
						String mmName = ((ModelType)wEl).getName();
						errorMessage = "Could not find metamodel '" + mmName + "'";
					}
					
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							MessageDialog.openError(
									shell,
									"Wires Error",
									"Error: "+ errorMessage);
						}
					}); 
					
					return Status.CANCEL_STATUS;
					
				}catch(QueryFailedException e){
					WiresElement wEl = e.getWiresElement();					
					String transName = ((Query)wEl).getName();
					
					errorMessage = "Query '" +transName + "' failed";
					
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							MessageDialog.openError(
									shell,
									"Wires Error",
									"Error: "+ errorMessage);
						}
					}); 
					
					return Status.CANCEL_STATUS;
					
				}catch(ResourceNotFoundException e){
					WiresElement wEl = e.getWiresElement();					
					String elementName = ((ConnectableElement)wEl).getName();
					
					errorMessage = "Path not found for '" +
								   elementName + "'" + " element";
					
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							MessageDialog.openError(
									shell,
									"Wires Error",
									"Error: "+ errorMessage);
						}
					}); 
					
					e.printStackTrace();
					return Status.CANCEL_STATUS;
					
				}catch(TypeNotFoundException e){
					WiresElement wEl = e.getWiresElement();					
					String elementName = ((ConnectableElement)wEl).getName();
					
					errorMessage = "Type not found at '" +
								   elementName + "'" + " element";
					
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							MessageDialog.openError(
									shell,
									"Wires Error",
									"Error: "+ errorMessage);
						}
					}); 
					e.printStackTrace();
					return Status.CANCEL_STATUS;
					
				}catch(Exception e){	
					
					errorMessage = e.getMessage();

					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							MessageDialog.openError(
									shell,
									"Wires Error",
									"Error: "+ errorMessage);
						}
					}); 
					e.printStackTrace();
					return Status.CANCEL_STATUS;
				}finally{
					try {
						Runtime r = Runtime.getRuntime();
						r.gc();
						ResourcesPlugin.getWorkspace().getRoot().refreshLocal(IResource.DEPTH_INFINITE, null);
						if (ok){
							Display.getDefault().syncExec(new Runnable() {
								public void run() {
									MessageDialog.openInformation(
											shell,
											"Wires*",
									"Transformation chain executed successfully!");
								}
							});
						}
					} catch (CoreException e) {
						Display.getDefault().syncExec(new Runnable() {
							public void run() {
								MessageDialog.openError(
										shell,
										"Wires Error",
										"Error: Cannot refresh workspace.");
							}
						});
					}
				}
			}
		};

		job.setPriority(Job.SHORT);
		job.schedule(); // start as soon as possible		
	}

	/**
	 * @see IActionDelegate#selectionChanged(IAction, ISelection)
	 */
	public void selectionChanged(IAction action, ISelection selection) {
		IStructuredSelection structured = (IStructuredSelection)selection;
        Object object = structured.getFirstElement();
        if (object instanceof IFile) {
            IFile file = (IFile) object;
            filePath = file.getLocation().toOSString();
            //filePath = file.getName().toString();
            path=filePath.substring(0, filePath.lastIndexOf(file.getName()));
        }
	}

}
